home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 83 / MacAddict_083_2003-07.iso / mac / Software / Development / VLC Source 0.5.3.dmg / src / misc / threads.c < prev    next >
C/C++ Source or Header  |  2003-04-07  |  25KB  |  825 lines

  1. /*****************************************************************************
  2.  * threads.c : threads implementation for the VideoLAN client
  3.  *****************************************************************************
  4.  * Copyright (C) 1999, 2000, 2001, 2002 VideoLAN
  5.  * $Id: threads.c,v 1.40 2003/03/10 00:04:14 massiot Exp $
  6.  *
  7.  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
  8.  *          Samuel Hocevar <sam@zoy.org>
  9.  *          Gildas Bazin <gbazin@netcourrier.com>
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  24.  *****************************************************************************/
  25.  
  26. #include <vlc/vlc.h>
  27.  
  28. #include <stdlib.h>
  29.  
  30. #define VLC_THREADS_UNINITIALIZED  0
  31. #define VLC_THREADS_PENDING        1
  32. #define VLC_THREADS_ERROR          2
  33. #define VLC_THREADS_READY          3
  34.  
  35. /*****************************************************************************
  36.  * Global mutex for lazy initialization of the threads system
  37.  *****************************************************************************/
  38. static volatile int i_initializations = 0;
  39.  
  40. #if defined( PTH_INIT_IN_PTH_H )
  41. #elif defined( ST_INIT_IN_ST_H )
  42. #elif defined( UNDER_CE )
  43. #elif defined( WIN32 )
  44. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  45.     static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
  46. #elif defined( HAVE_CTHREADS_H )
  47. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  48. #endif
  49.  
  50. /*****************************************************************************
  51.  * Global variable for named mutexes
  52.  *****************************************************************************/
  53. typedef struct vlc_namedmutex_t vlc_namedmutex_t;
  54. struct vlc_namedmutex_t
  55. {
  56.     vlc_mutex_t lock;
  57.  
  58.     char *psz_name;
  59.     int i_usage;
  60.     vlc_namedmutex_t *p_next;
  61. };
  62.  
  63. /*****************************************************************************
  64.  * vlc_threads_init: initialize threads system
  65.  *****************************************************************************
  66.  * This function requires lazy initialization of a global lock in order to
  67.  * keep the library really thread-safe. Some architectures don't support this
  68.  * and thus do not guarantee the complete reentrancy.
  69.  *****************************************************************************/
  70. int __vlc_threads_init( vlc_object_t *p_this )
  71. {
  72.     static volatile int i_status = VLC_THREADS_UNINITIALIZED;
  73.  
  74.     libvlc_t *p_libvlc = (libvlc_t *)p_this;
  75.     int i_ret = VLC_SUCCESS;
  76.  
  77.     /* If we have lazy mutex initialization, use it. Otherwise, we just
  78.      * hope nothing wrong happens. */
  79. #if defined( PTH_INIT_IN_PTH_H )
  80. #elif defined( ST_INIT_IN_ST_H )
  81. #elif defined( UNDER_CE )
  82. #elif defined( WIN32 )
  83.     HINSTANCE hInstLib;
  84. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  85.     pthread_mutex_lock( &once_mutex );
  86. #elif defined( HAVE_CTHREADS_H )
  87. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  88. #endif
  89.  
  90.     if( i_status == VLC_THREADS_UNINITIALIZED )
  91.     {
  92.         i_status = VLC_THREADS_PENDING;
  93.  
  94.         /* We should be safe now. Do all the initialization stuff we want. */
  95.         p_libvlc->b_ready = VLC_FALSE;
  96.  
  97. #if defined( PTH_INIT_IN_PTH_H )
  98.         i_ret = ( pth_init() == FALSE );
  99.  
  100. #elif defined( ST_INIT_IN_ST_H )
  101.         i_ret = st_init();
  102.  
  103. #elif defined( UNDER_CE )
  104.         /* Nothing to initialize */
  105.  
  106. #elif defined( WIN32 )
  107.         /* Dynamically get the address of SignalObjectAndWait */
  108.         if( GetVersion() < 0x80000000 )
  109.         {
  110.             /* We are running on NT/2K/XP, we can use SignalObjectAndWait */
  111.             hInstLib = LoadLibrary( "kernel32" );
  112.             if( hInstLib )
  113.             {
  114.                 p_libvlc->SignalObjectAndWait =
  115.                     (SIGNALOBJECTANDWAIT)GetProcAddress( hInstLib,
  116.                                                      "SignalObjectAndWait" );
  117.             }
  118.         }
  119.         else
  120.         {
  121.             p_libvlc->SignalObjectAndWait = NULL;
  122.         }
  123.  
  124.         p_libvlc->b_fast_mutex = 0;
  125.         p_libvlc->i_win9x_cv = 0;
  126.  
  127. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  128. #elif defined( HAVE_CTHREADS_H )
  129. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  130. #endif
  131.  
  132.         vlc_object_create( p_libvlc, VLC_OBJECT_ROOT );
  133.  
  134.         if( i_ret )
  135.         {
  136.             i_status = VLC_THREADS_ERROR;
  137.         }
  138.         else
  139.         {
  140.             i_initializations++;
  141.             i_status = VLC_THREADS_READY;
  142.         }
  143.     }
  144.     else
  145.     {
  146.         /* Just increment the initialization count */
  147.         i_initializations++;
  148.     }
  149.  
  150.     /* If we have lazy mutex initialization support, unlock the mutex;
  151.      * otherwize, do a naive wait loop. */
  152. #if defined( PTH_INIT_IN_PTH_H )
  153.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  154. #elif defined( ST_INIT_IN_ST_H )
  155.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  156. #elif defined( UNDER_CE )
  157.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  158. #elif defined( WIN32 )
  159.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  160. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  161.     pthread_mutex_unlock( &once_mutex );
  162. #elif defined( HAVE_CTHREADS_H )
  163.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  164. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  165.     while( i_status == VLC_THREADS_PENDING ) msleep( THREAD_SLEEP );
  166. #endif
  167.  
  168.     if( i_status != VLC_THREADS_READY )
  169.     {
  170.         return VLC_ETHREAD;
  171.     }
  172.  
  173.     return i_ret;
  174. }
  175.  
  176. /*****************************************************************************
  177.  * vlc_threads_end: stop threads system
  178.  *****************************************************************************
  179.  * FIXME: This function is far from being threadsafe. We should undo exactly
  180.  * what we did above in vlc_threads_init.
  181.  *****************************************************************************/
  182. int __vlc_threads_end( vlc_object_t *p_this )
  183. {
  184. #if defined( PTH_INIT_IN_PTH_H )
  185.     i_initializations--;
  186.     if( i_initializations == 0 )
  187.     {
  188.         return ( pth_kill() == FALSE );
  189.     }
  190.  
  191. #elif defined( ST_INIT_IN_ST_H )
  192.     i_initializations--;
  193.  
  194. #elif defined( UNDER_CE )
  195.     i_initializations--;
  196.  
  197. #elif defined( WIN32 )
  198.     i_initializations--;
  199.  
  200. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  201.     pthread_mutex_lock( &once_mutex );
  202.     i_initializations--;
  203.     pthread_mutex_unlock( &once_mutex );
  204.  
  205. #elif defined( HAVE_CTHREADS_H )
  206.     i_initializations--;
  207.  
  208. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  209.     i_initializations--;
  210.  
  211. #endif
  212.     return VLC_SUCCESS;
  213. }
  214.  
  215. /*****************************************************************************
  216.  * Prototype for GPROF wrapper
  217.  *****************************************************************************/
  218. #ifdef GPROF
  219. typedef void *(*vlc_thread_func_t)(void *p_data);
  220.  
  221. /* Wrapper function for profiling */
  222. static void *      vlc_thread_wrapper ( void *p_wrapper );
  223.  
  224. #   if defined( WIN32 ) && !defined( UNDER_CE )
  225.  
  226. #       define ITIMER_REAL 1
  227. #       define ITIMER_PROF 2
  228.  
  229. struct itimerval
  230. {
  231.     struct timeval it_value;
  232.     struct timeval it_interval;
  233. };
  234.  
  235. int setitimer(int kind, const struct itimerval* itnew, struct itimerval* itold);
  236. #   endif /* WIN32 && !UNDER_CE */
  237.  
  238. typedef struct wrapper_t
  239. {
  240.     /* Data lock access */
  241.     vlc_mutex_t lock;
  242.     vlc_cond_t  wait;
  243.  
  244.     /* Data used to spawn the real thread */
  245.     vlc_thread_func_t func;
  246.     void *p_data;
  247.  
  248.     /* Profiling timer passed to the thread */
  249.     struct itimerval itimer;
  250.  
  251. } wrapper_t;
  252.  
  253. #endif /* GPROF */
  254.  
  255. /*****************************************************************************
  256.  * vlc_mutex_init: initialize a mutex
  257.  *****************************************************************************/
  258. int __vlc_mutex_init( vlc_object_t *p_this, vlc_mutex_t *p_mutex )
  259. {
  260.     p_mutex->p_this = p_this;
  261.  
  262. #if defined( PTH_INIT_IN_PTH_H )
  263.     return ( pth_mutex_init( &p_mutex->mutex ) == FALSE );
  264.  
  265. #elif defined( ST_INIT_IN_ST_H )
  266.     p_mutex->mutex = st_mutex_new();
  267.     return ( p_mutex->mutex == NULL ) ? errno : 0;
  268.  
  269. #elif defined( UNDER_CE )
  270.     InitializeCriticalSection( &p_mutex->csection );
  271.     return 0;
  272.  
  273. #elif defined( WIN32 )
  274.     /* We use mutexes on WinNT/2K/XP because we can use the SignalObjectAndWait
  275.      * function and have a 100% correct vlc_cond_wait() implementation.
  276.      * As this function is not available on Win9x, we can use the faster
  277.      * CriticalSections */
  278.     if( p_this->p_libvlc->SignalObjectAndWait &&
  279.         !p_this->p_libvlc->b_fast_mutex )
  280.     {
  281.         /* We are running on NT/2K/XP, we can use SignalObjectAndWait */
  282.         p_mutex->mutex = CreateMutex( 0, FALSE, 0 );
  283.         return ( p_mutex->mutex != NULL ? 0 : 1 );
  284.     }
  285.     else
  286.     {
  287.         p_mutex->mutex = NULL;
  288.         InitializeCriticalSection( &p_mutex->csection );
  289.         return 0;
  290.     }
  291.  
  292. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  293. #   if defined(DEBUG) && defined(SYS_LINUX)
  294.     {
  295.         /* Create error-checking mutex to detect problems more easily. */
  296.         pthread_mutexattr_t attr;
  297.         int                 i_result;
  298.  
  299.         pthread_mutexattr_init( &attr );
  300.         pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
  301.         i_result = pthread_mutex_init( &p_mutex->mutex, &attr );
  302.         pthread_mutexattr_destroy( &attr );
  303.         return( i_result );
  304.     }
  305. #   endif
  306.     return pthread_mutex_init( &p_mutex->mutex, NULL );
  307.  
  308. #elif defined( HAVE_CTHREADS_H )
  309.     mutex_init( p_mutex );
  310.     return 0;
  311.  
  312. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  313.     /* check the arguments and whether it's already been initialized */
  314.     if( p_mutex == NULL )
  315.     {
  316.         return B_BAD_VALUE;
  317.     }
  318.  
  319.     if( p_mutex->init == 9999 )
  320.     {
  321.         return EALREADY;
  322.     }
  323.  
  324.     p_mutex->lock = create_sem( 1, "BeMutex" );
  325.     if( p_mutex->lock < B_NO_ERROR )
  326.     {
  327.         return( -1 );
  328.     }
  329.  
  330.     p_mutex->init = 9999;
  331.     return B_OK;
  332.  
  333. #endif
  334. }
  335.  
  336. /*****************************************************************************
  337.  * vlc_mutex_destroy: destroy a mutex, inner version
  338.  *****************************************************************************/
  339. int __vlc_mutex_destroy( char * psz_file, int i_line, vlc_mutex_t *p_mutex )
  340. {
  341.     int i_result;
  342.     /* In case of error : */
  343.     int i_thread = -1;
  344.     const char * psz_error = "";
  345.  
  346. #if defined( PTH_INIT_IN_PTH_H )
  347.     return 0;
  348.  
  349. #elif defined( ST_INIT_IN_ST_H )
  350.     i_result = st_mutex_destroy( p_mutex->mutex );
  351.  
  352. #elif defined( UNDER_CE )
  353.     DeleteCriticalSection( &p_mutex->csection );
  354.     return 0;
  355.  
  356. #elif defined( WIN32 )
  357.     if( p_mutex->mutex )
  358.     {
  359.         CloseHandle( p_mutex->mutex );
  360.     }
  361.     else
  362.     {
  363.         DeleteCriticalSection( &p_mutex->csection );
  364.     }
  365.     return 0;
  366.  
  367. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  368.     i_result = pthread_mutex_destroy( &p_mutex->mutex );
  369.     if ( i_result )
  370.     {
  371.         i_thread = (int)pthread_self();
  372.         psz_error = strerror(i_result);
  373.     }
  374.  
  375. #elif defined( HAVE_CTHREADS_H )
  376.     return 0;
  377.  
  378. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  379.     if( p_mutex->init == 9999 )
  380.     {
  381.         delete_sem( p_mutex->lock );
  382.     }
  383.  
  384.     p_mutex->init = 0;
  385.     return B_OK;
  386. #endif
  387.  
  388.     if( i_result )
  389.     {
  390.         msg_Err( p_mutex->p_this,
  391.                  "thread %d: mutex_destroy failed at %s:%d (%d:%s)",
  392.                  i_thread, psz_file, i_line, i_result, psz_error );
  393.     }
  394.     return i_result;
  395. }
  396.  
  397. /*****************************************************************************
  398.  * vlc_cond_init: initialize a condition
  399.  *****************************************************************************/
  400. int __vlc_cond_init( vlc_object_t *p_this, vlc_cond_t *p_condvar )
  401. {
  402.     p_condvar->p_this = p_this;
  403.  
  404. #if defined( PTH_INIT_IN_PTH_H )
  405.     return ( pth_cond_init( &p_condvar->cond ) == FALSE );
  406.  
  407. #elif defined( ST_INIT_IN_ST_H )
  408.     p_condvar->cond = st_cond_new();
  409.     return ( p_condvar->cond == NULL ) ? errno : 0;
  410.  
  411. #elif defined( UNDER_CE )
  412.     /* Initialize counter */
  413.     p_condvar->i_waiting_threads = 0;
  414.  
  415.     /* Create an auto-reset event. */
  416.     p_condvar->event = CreateEvent( NULL,   /* no security */
  417.                                     FALSE,  /* auto-reset event */
  418.                                     FALSE,  /* start non-signaled */
  419.                                     NULL ); /* unnamed */
  420.     return !p_condvar->event;
  421.  
  422. #elif defined( WIN32 )
  423.     /* Initialize counter */
  424.     p_condvar->i_waiting_threads = 0;
  425.  
  426.     /* Misc init */
  427.     p_condvar->i_win9x_cv = p_this->p_libvlc->i_win9x_cv;
  428.     p_condvar->SignalObjectAndWait = p_this->p_libvlc->SignalObjectAndWait;
  429.  
  430.     if( (p_condvar->SignalObjectAndWait && !p_this->p_libvlc->b_fast_mutex)
  431.         || p_condvar->i_win9x_cv == 0 )
  432.     {
  433.         /* Create an auto-reset event. */
  434.         p_condvar->event = CreateEvent( NULL,   /* no security */
  435.                                         FALSE,  /* auto-reset event */
  436.                                         FALSE,  /* start non-signaled */
  437.                                         NULL ); /* unnamed */
  438.  
  439.         p_condvar->semaphore = NULL;
  440.         return !p_condvar->event;
  441.     }
  442.     else
  443.     {
  444.         p_condvar->semaphore = CreateSemaphore( NULL,       /* no security */
  445.                                                 0,          /* initial count */
  446.                                                 0x7fffffff, /* max count */
  447.                                                 NULL );     /* unnamed */
  448.  
  449.         if( p_condvar->i_win9x_cv == 1 )
  450.             /* Create a manual-reset event initially signaled. */
  451.             p_condvar->event = CreateEvent( NULL, TRUE, TRUE, NULL );
  452.         else
  453.             /* Create a auto-reset event. */
  454.             p_condvar->event = CreateEvent( NULL, FALSE, FALSE, NULL );
  455.  
  456.         InitializeCriticalSection( &p_condvar->csection );
  457.  
  458.         return !p_condvar->semaphore || !p_condvar->event;
  459.     }
  460.  
  461. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  462.     return pthread_cond_init( &p_condvar->cond, NULL );
  463.  
  464. #elif defined( HAVE_CTHREADS_H )
  465.     /* condition_init() */
  466.     spin_lock_init( &p_condvar->lock );
  467.     cthread_queue_init( &p_condvar->queue );
  468.     p_condvar->name = 0;
  469.     p_condvar->implications = 0;
  470.  
  471.     return 0;
  472.  
  473. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  474.     if( !p_condvar )
  475.     {
  476.         return B_BAD_VALUE;
  477.     }
  478.  
  479.     if( p_condvar->init == 9999 )
  480.     {
  481.         return EALREADY;
  482.     }
  483.  
  484.     p_condvar->thread = -1;
  485.     p_condvar->init = 9999;
  486.     return 0;
  487. #endif
  488. }
  489.  
  490. /*****************************************************************************
  491.  * vlc_cond_destroy: destroy a condition, inner version
  492.  *****************************************************************************/
  493. int __vlc_cond_destroy( char * psz_file, int i_line, vlc_cond_t *p_condvar )
  494. {
  495.     int i_result;
  496.     /* In case of error : */
  497.     int i_thread = -1;
  498.     const char * psz_error = "";
  499.  
  500. #if defined( PTH_INIT_IN_PTH_H )
  501.     return 0;
  502.  
  503. #elif defined( ST_INIT_IN_ST_H )
  504.     i_result = st_cond_destroy( p_condvar->cond );
  505.  
  506. #elif defined( UNDER_CE )
  507.     i_result = !CloseHandle( p_condvar->event );
  508.  
  509. #elif defined( WIN32 )
  510.     if( !p_condvar->semaphore )
  511.         i_result = !CloseHandle( p_condvar->event );
  512.     else
  513.         i_result = !CloseHandle( p_condvar->event )
  514.           || !CloseHandle( p_condvar->semaphore );
  515.  
  516. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  517.     i_result = pthread_cond_destroy( &p_condvar->cond );
  518.     if ( i_result )
  519.     {
  520.         i_thread = (int)pthread_self();
  521.         psz_error = strerror(i_result);
  522.     }
  523.  
  524. #elif defined( HAVE_CTHREADS_H )
  525.     return 0;
  526.  
  527. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  528.     p_condvar->init = 0;
  529.     return 0;
  530. #endif
  531.  
  532.     if( i_result )
  533.     {
  534.         msg_Err( p_condvar->p_this,
  535.                  "thread %d: cond_destroy failed at %s:%d (%d:%s)",
  536.                  i_thread, psz_file, i_line, i_result, psz_error );
  537.     }
  538.     return i_result;
  539. }
  540.  
  541. /*****************************************************************************
  542.  * vlc_thread_create: create a thread, inner version
  543.  *****************************************************************************
  544.  * Note that i_priority is only taken into account on platforms supporting
  545.  * userland real-time priority threads.
  546.  *****************************************************************************/
  547. int __vlc_thread_create( vlc_object_t *p_this, char * psz_file, int i_line,
  548.                          char *psz_name, void * ( *func ) ( void * ),
  549.                          int i_priority, vlc_bool_t b_wait )
  550. {
  551.     int i_ret;
  552.     void *p_data;
  553.  
  554.     vlc_mutex_lock( &p_this->object_lock );
  555.  
  556. #ifdef GPROF
  557.     wrapper_t wrapper;
  558.  
  559.     /* Initialize the wrapper structure */
  560.     wrapper.func = func;
  561.     wrapper.p_data = (void *)p_this;
  562.     getitimer( ITIMER_PROF, &wrapper.itimer );
  563.     vlc_mutex_init( p_this, &wrapper.lock );
  564.     vlc_cond_init( p_this, &wrapper.wait );
  565.     vlc_mutex_lock( &wrapper.lock );
  566.  
  567.     /* Alter user-passed data so that we call the wrapper instead
  568.      * of the real function */
  569.     p_data = &wrapper;
  570.     func = vlc_thread_wrapper;
  571. #else
  572.     p_data = (void *)p_this;
  573. #endif
  574.  
  575. #if defined( PTH_INIT_IN_PTH_H )
  576.     p_this->thread_id = pth_spawn( PTH_ATTR_DEFAULT, func, p_data );
  577.     i_ret = p_this->thread_id == NULL;
  578.  
  579. #elif defined( ST_INIT_IN_ST_H )
  580.     p_this->thread_id = st_thread_create( func, p_data, 1, 0 );
  581.     i_ret = 0;
  582.  
  583. #elif defined( WIN32 ) || defined( UNDER_CE )
  584.     {
  585.         unsigned threadID;
  586.         /* When using the MSVCRT C library you have to use the _beginthreadex
  587.          * function instead of CreateThread, otherwise you'll end up with
  588.          * memory leaks and the signal functions not working (see Microsoft
  589.          * Knowledge Base, article 104641) */
  590.         p_this->thread_id =
  591. #if defined( UNDER_CE )
  592.                 (HANDLE)CreateThread( NULL, 0, (PTHREAD_START) func,
  593.                                       p_data, 0, &threadID );
  594. #else
  595.                 (HANDLE)_beginthreadex( NULL, 0, (PTHREAD_START) func,
  596.                                         p_data, 0, &threadID );
  597. #endif
  598.     }
  599.  
  600.     if ( p_this->thread_id && i_priority )
  601.     {
  602.         if ( !SetThreadPriority(p_this->thread_id, i_priority) )
  603.         {
  604.             msg_Warn( p_this, "couldn't set a faster priority" );
  605.             i_priority = 0;
  606.         }
  607.     }
  608.  
  609.     i_ret = ( p_this->thread_id ? 0 : 1 );
  610.  
  611. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  612.     i_ret = pthread_create( &p_this->thread_id, NULL, func, p_data );
  613.  
  614. #ifdef SYS_DARWIN
  615.     if ( i_priority )
  616.     {
  617.         int i_error, i_policy;
  618.         struct sched_param param;
  619.         memset( ¶m, 0, sizeof(struct sched_param) );
  620.         if ( i_priority < 0 )
  621.         {
  622.             param.sched_priority = (-1) * i_priority;
  623.             i_policy = SCHED_OTHER;
  624.         }
  625.         else
  626.         {
  627.             param.sched_priority = i_priority;
  628.             i_policy = SCHED_RR;
  629.         }
  630.         if ( (i_error = pthread_setschedparam( p_this->thread_id,
  631.                                                i_policy, ¶m )) )
  632.         {
  633.             msg_Warn( p_this, "couldn't set thread priority (%s:%d): %s",
  634.                       psz_file, i_line, strerror(i_error) );
  635.             i_priority = 0;
  636.         }
  637.     }
  638. #endif
  639.  
  640. #elif defined( HAVE_CTHREADS_H )
  641.     p_this->thread_id = cthread_fork( (cthread_fn_t)func, (any_t)p_data );
  642.     i_ret = 0;
  643.  
  644. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  645.     p_this->thread_id = spawn_thread( (thread_func)func, psz_name,
  646.                                       i_priority, p_data );
  647.     i_ret = resume_thread( p_this->thread_id );
  648.  
  649. #endif
  650.  
  651. #ifdef GPROF
  652.     if( i_ret == 0 )
  653.     {
  654.         vlc_cond_wait( &wrapper.wait, &wrapper.lock );
  655.     }
  656.  
  657.     vlc_mutex_unlock( &wrapper.lock );
  658.     vlc_mutex_destroy( &wrapper.lock );
  659.     vlc_cond_destroy( &wrapper.wait );
  660. #endif
  661.  
  662.     if( i_ret == 0 )
  663.     {
  664.         if( b_wait )
  665.         {
  666.             msg_Dbg( p_this, "waiting for thread completion" );
  667.             vlc_cond_wait( &p_this->object_wait, &p_this->object_lock );
  668.         }
  669.  
  670.         p_this->b_thread = 1;
  671.  
  672.         msg_Dbg( p_this, "thread %d (%s) created at priority %d (%s:%d)",
  673.                  (int)p_this->thread_id, psz_name, i_priority,
  674.                  psz_file, i_line );
  675.  
  676.         vlc_mutex_unlock( &p_this->object_lock );
  677.     }
  678.     else
  679.     {
  680. #ifdef HAVE_STRERROR
  681.         msg_Err( p_this, "%s thread could not be created at %s:%d (%s)",
  682.                          psz_name, psz_file, i_line, strerror(i_ret) );
  683. #else
  684.         msg_Err( p_this, "%s thread could not be created at %s:%d",
  685.                          psz_name, psz_file, i_line );
  686. #endif
  687.         vlc_mutex_unlock( &p_this->object_lock );
  688.     }
  689.  
  690.     return i_ret;
  691. }
  692.  
  693. /*****************************************************************************
  694.  * vlc_thread_set_priority: set the priority of the current thread when we
  695.  * couldn't set it in vlc_thread_create (for instance for the main thread)
  696.  *****************************************************************************/
  697. int __vlc_thread_set_priority( vlc_object_t *p_this, char * psz_file,
  698.                                int i_line, int i_priority )
  699. {
  700. #if defined( PTH_INIT_IN_PTH_H ) || defined( ST_INIT_IN_ST_H )
  701. #elif defined( WIN32 ) || defined( UNDER_CE )
  702.     if ( !SetThreadPriority(GetCurrentThread(), i_priority) )
  703.     {
  704.         msg_Warn( p_this, "couldn't set a faster priority" );
  705.         return 1;
  706.     }
  707.  
  708. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  709.  
  710. #ifdef SYS_DARWIN
  711.     if ( i_priority )
  712.     {
  713.         int i_error, i_policy;
  714.         struct sched_param param;
  715.         memset( ¶m, 0, sizeof(struct sched_param) );
  716.         if ( i_priority < 0 )
  717.         {
  718.             param.sched_priority = (-1) * i_priority;
  719.             i_policy = SCHED_OTHER;
  720.         }
  721.         else
  722.         {
  723.             param.sched_priority = i_priority;
  724.             i_policy = SCHED_RR;
  725.         }
  726.         if ( (i_error = pthread_setschedparam( pthread_self(),
  727.                                                i_policy, ¶m )) )
  728.         {
  729.             msg_Warn( p_this, "couldn't set thread priority (%s:%d): %s",     
  730.                       psz_file, i_line, strerror(i_error) );
  731.             i_priority = 0;
  732.         }
  733.     }
  734. #endif
  735.  
  736. #endif
  737.  
  738.     return 0;
  739. }
  740.  
  741. /*****************************************************************************
  742.  * vlc_thread_ready: tell the parent thread we were successfully spawned
  743.  *****************************************************************************/
  744. void __vlc_thread_ready( vlc_object_t *p_this )
  745. {
  746.     vlc_mutex_lock( &p_this->object_lock );
  747.     vlc_cond_signal( &p_this->object_wait );
  748.     vlc_mutex_unlock( &p_this->object_lock );
  749. }
  750.  
  751. /*****************************************************************************
  752.  * vlc_thread_join: wait until a thread exits, inner version
  753.  *****************************************************************************/
  754. void __vlc_thread_join( vlc_object_t *p_this, char * psz_file, int i_line )
  755. {
  756.     int i_ret = 0;
  757.  
  758. #if defined( PTH_INIT_IN_PTH_H )
  759.     i_ret = ( pth_join( p_this->thread_id, NULL ) == FALSE );
  760.  
  761. #elif defined( ST_INIT_IN_ST_H )
  762.     i_ret = st_thread_join( p_this->thread_id, NULL );
  763.  
  764. #elif defined( UNDER_CE )
  765.     WaitForSingleObject( p_this->thread_id, INFINITE );
  766.  
  767. #elif defined( WIN32 )
  768.     WaitForSingleObject( p_this->thread_id, INFINITE );
  769.  
  770. #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
  771.     i_ret = pthread_join( p_this->thread_id, NULL );
  772.  
  773. #elif defined( HAVE_CTHREADS_H )
  774.     cthread_join( p_this->thread_id );
  775.     i_ret = 1;
  776.  
  777. #elif defined( HAVE_KERNEL_SCHEDULER_H )
  778.     int32 exit_value;
  779.     wait_for_thread( p_this->thread_id, &exit_value );
  780.  
  781. #endif
  782.  
  783.     if( i_ret )
  784.     {
  785. #ifdef HAVE_STRERROR
  786.         msg_Err( p_this, "thread_join(%d) failed at %s:%d (%s)",
  787.                          (int)p_this->thread_id, psz_file, i_line,
  788.                          strerror(i_ret) );
  789. #else
  790.         msg_Err( p_this, "thread_join(%d) failed at %s:%d",
  791.                          (int)p_this->thread_id, psz_file, i_line );
  792. #endif
  793.     }
  794.     else
  795.     {
  796.         msg_Dbg( p_this, "thread %d joined (%s:%d)",
  797.                          (int)p_this->thread_id, psz_file, i_line );
  798.     }
  799.  
  800.     p_this->b_thread = 0;
  801. }
  802.  
  803. /*****************************************************************************
  804.  * vlc_thread_wrapper: wrapper around thread functions used when profiling.
  805.  *****************************************************************************/
  806. #ifdef GPROF
  807. static void *vlc_thread_wrapper( void *p_wrapper )
  808. {
  809.     /* Put user data in thread-local variables */
  810.     void *            p_data = ((wrapper_t*)p_wrapper)->p_data;
  811.     vlc_thread_func_t func   = ((wrapper_t*)p_wrapper)->func;
  812.  
  813.     /* Set the profile timer value */
  814.     setitimer( ITIMER_PROF, &((wrapper_t*)p_wrapper)->itimer, NULL );
  815.  
  816.     /* Tell the calling thread that we don't need its data anymore */
  817.     vlc_mutex_lock( &((wrapper_t*)p_wrapper)->lock );
  818.     vlc_cond_signal( &((wrapper_t*)p_wrapper)->wait );
  819.     vlc_mutex_unlock( &((wrapper_t*)p_wrapper)->lock );
  820.  
  821.     /* Call the real function */
  822.     return func( p_data );
  823. }
  824. #endif
  825.